/**
 * 
 */
package com.db.stockexchange.server.orderbook;

import com.db.stockexchange.common.OrderSide;
import com.db.stockexchange.common.OrderStatus;

/**
 * @author Rayman
 * Order for sell/buy stock
 */
public class Order {
	static final String MES_ILLEGAL_SHARE_NUMBER = "Share number is illegal. It should be positive integer value";
	static final String MES_ILLEGAL_PRICE = "Price is illegal. It should be positive value";
	
	private int id;
	private String clientId;
	private String tickerName;
	private int shareNumber;
	private Price price;
	private OrderSide side;
	private OrderStatus status;
	private boolean useBestMarketPrice;
	private int leavesShareNumber;

	public Order(int id, String clientId, String ticker, int shareNumber, OrderSide side) {
		super();
		this.id = id;
		this.clientId = clientId;
		this.tickerName = ticker;
		this.shareNumber = shareNumber;
		this.leavesShareNumber = shareNumber;
		this.price = null;
		this.side = side;		 
		this.status = OrderStatus.NEW;
		this.useBestMarketPrice = true;
	}
	
	public Order(int id, String clientId, String ticker, int shareNumber, float price, OrderSide side) {
		super();
		this.id = id;
		this.clientId = clientId;
		this.tickerName = ticker;
		this.shareNumber = shareNumber;
		this.leavesShareNumber = shareNumber;
		this.price = new Price(price);
		this.side = side;		 
		this.status = OrderStatus.NEW;
		this.useBestMarketPrice = false;
	}

	public Order(Order order) {
		this.id = order.id;
		this.clientId = order.clientId;
		this.tickerName = order.tickerName;
		this.shareNumber = order.shareNumber;
		this.leavesShareNumber = order.leavesShareNumber;
		this.price = order.price;
		this.side = order.side;
		this.status = order.status;
		this.useBestMarketPrice = order.useBestMarketPrice;
	}

	public int getId() {
		return id;
	}

	public String getClientId() {
		return clientId;
	}

	public String getTickerName() {
		return tickerName;
	}
	
	public int getOrderQuantity() {
		return shareNumber;
	}

	public void setOrderQuantity(int shareNumber) throws IllegalOrderException {
		if (this.status != OrderStatus.NEW)
			throw new IllegalOrderException("Could not change number of share because order status is not <NEW>");
		
		if (checkShareNumber(shareNumber)) {
			this.shareNumber = shareNumber;
			this.leavesShareNumber = shareNumber;
		}
	}	
	
	public int getLeavesQuantity() {
		return leavesShareNumber;		
	}
	
	public int getCumQuantity() {
		return shareNumber - leavesShareNumber;
	}
	
	/**
	 * Partially or fully filled order 
	 * @param shareNumber Positive value, should be less or equals to share number of order to successful filling
	 * @return Returns true if filling is success, else returns false
	 */
	boolean fill(int shareNumber) {
		if (shareNumber <= 0 || this.leavesShareNumber < shareNumber)
			return false;
		
		this.leavesShareNumber -= shareNumber;
		if (this.leavesShareNumber == 0)
			status = OrderStatus.FILLED;
		else
			status = OrderStatus.PARTIALLY_FILLED;
		
		return true;
	}
	
	public Price getPrice() {
		return price;
	}

	public OrderSide getSide() {
		return side;
	}
	
	public OrderStatus getStatus() {
		return status;
	}

	public boolean isUseBestMarketPrice() {
		return useBestMarketPrice;
	}

	/**
	 * Enable using best market price
	 */
	public void useBestMarketPrice() {
		this.useBestMarketPrice = true;
	}
	
	/**
	 * Disable using best market price and set specified price
	 * @param price Specified price
	 */
	public void useSpecifiedPrice(Price price) throws IllegalOrderException {
		if (checkPrice(price))
			this.price = price;
		
		useBestMarketPrice = false;
	}

	private boolean checkShareNumber(int shareNumber) throws IllegalOrderException {
		if (shareNumber <= 0)
			throw new IllegalOrderException(MES_ILLEGAL_SHARE_NUMBER);
		
		return true;
	}
	
	private boolean checkPrice(Price price) throws IllegalOrderException {
		if (Float.isNaN(price.getValue()) || price.getValue() <= 0)
			throw new IllegalOrderException(MES_ILLEGAL_PRICE);
		
		return true;
	}
	
	@Override
	public String toString() {
		return "Order: " + clientId + ":" + id + " <" + tickerName + ">";
	}
}
